package solitaire.gui;

import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Point2D;
import java.sql.Time;
import java.util.ArrayList;
import javax.swing.JPanel;

import solitaire.deck.*;
import solitaire.core.*;

public class PlayPanel extends JPanel {

	private static final long serialVersionUID = 98;
	private PileCollection _acesPiles;
	private PileCollection _playPiles;
	private Card _currentCard;
	private Pile _currentPile;
	private CardCollection _trailList;
	private Deck _deck;
	public PlayPanel()
	{
		_deck = new Deck();
		_acesPiles = new PileCollection();
		_playPiles = new PileCollection();
		_trailList = new CardCollection();

		addMouseListener(new MouseHandler());
		addMouseMotionListener(new MouseMotionHandler());
	}
	
	public void newGame() {
		_acesPiles.clear();
		_playPiles.clear();
		_trailList.clear();
		
		// Move to right so piles are at the right side
		// TODO: use toolkit to calculate
		/*
		 * Toolkit kit = Toolkit.getDefaultToolkit(); Dimension screenSize =
		 * kit.getScreenSize()
		 */
		
		int offset = (85 * 4);

		for (int i = 1; i <= 4; i++) {
			_acesPiles.add(new AcesPile(i, (i * 85) + offset, 50));
		}

		for (int i = 1; i <= 8; i++) {
			_playPiles.add(new PlayPile(i, (85 * i), 170));
		}

		
		_deck.shuffle();
		
		arrangeCards(_deck);

		repaint();
	}
	
	public void sameGame()
	{
		_acesPiles.removeAllCards();
		_playPiles.removeAllCards();
		_trailList.clear();
		
		arrangeCards(_deck);

		repaint();
	}

	public void paintComponent(Graphics g) {

		super.paintComponent(g);

		_acesPiles.paintComponent(g);
		_playPiles.paintComponent(g);
		
		if(_trailList != null)
		{
			for(Card card : _trailList)
			{
				card.drawObject( g );
			}
		}
	}
	
	private class BlinkThread extends Thread {
		Card _card = null;
		public BlinkThread(Card card) {
			_card = card;
		}
		
	    public void run () {
	        for (int i = 0; i < 2; ++i) { 
	        	//if(_card.isTurned())
	        	if(i == 0 || i == 2)
				{
	        		_card.storeLocation();
	        		_card.setLocation(_card.startX-10, _card.startY);
	        		//_card.turnCardDownSide();
				}
				else
				{
					//_card.turnCardUpSide();
					//_card.setLocation(_card.startX+10, _card.startY);
					_card.restoreLocation();
				}
				repaint();
				
				try {	
					//Thread.sleep (300); // milliseconds
					BlinkThread.sleep(300);
				} 
				catch (InterruptedException e) {
					// 	OK: just end run
				}
	        } 
	    }
	}  


	private boolean doTheHintTrail()
	{
		boolean result = false;
		for(Pile currentPile : _playPiles)
		{
			Card firstCard = currentPile.getCards().getLast();
			for(Pile comparePile : _playPiles)
			{
				for(Card card : comparePile.getCards())
				{
					if(card != null && firstCard != null)
					{
						if(card.getSuit() == firstCard.getSuit() &&
								card.getRank().getNr() == (firstCard.getRank().getNr()-1))
						{
							if(card.getPile() != firstCard.getPile() &&
									card.getPile().getClass() != AcesPile.class &&
									card.isTurned())
							{
								//currentPile.addTrailList(card.getTrailList());
								//comparePile.removeTrailList(card.getTrailList());
								
								Thread thread = new BlinkThread (card); 
								thread.start (); // indirectly calls the run method

								result = true;
							}
						}
					}
				}
			}
		}
		return result;
	}
	
	public void undoMove()
	{
		for(Pile pile : _acesPiles)
		{
			pile.removeTrailList(_trailList);
		}
		for(Pile pile : _playPiles)
		{
			pile.removeTrailList(_trailList);
		}
		_trailList.restoreLocation();
		_currentPile.addTrailList(_trailList);
		repaint();
	}
	
	private class MouseHandler extends MouseAdapter {
		public void mousePressed(MouseEvent event) {
			
			//TODO validate that card can be moved
			_currentCard = _playPiles.findCard( event.getPoint() );
			_currentPile = null;
			
			

			if (_currentCard != null) {
				_currentPile = _currentCard.getPile();
				if(_currentPile == null)
				{
					//TODO: throw exception - System.Diagonstic.Assert for java
					System.out.println("Exception");
				}
				_trailList = _currentCard.getTrailList();
				_trailList.storeLocation();
				_currentPile.removeTrailList(_trailList);
				
				if(Validator.MayTurnCard(_trailList))
				{
					_currentCard.turnCardUpSide();
				}
			}
		}
		
		public void mouseClicked( MouseEvent event )
        {
            if( event.getClickCount() >= 2 )
            {
            	Card card = _playPiles.findCard( event.getPoint() );
            	if(card != null)
            	{
            		_trailList = card.getTrailList();
            		if(Validator.IsTopMost(_trailList))
            		{
            			for(Pile pile : _acesPiles)
            			{
            				if(Validator.MayBePlacedOnAcePile((AcesPile)pile, _trailList))
            				{
            					card.getPile().removeTrailList(_trailList);
            					pile.addTrailList(_trailList);
            					repaint();
            					break;
            				}
            			}
            		}
            	}
            }
        }

		public void mouseReleased(MouseEvent event) {
			
			if(_currentCard == null)
			{
				if (!doTheHintTrail())
				{
					System.out.println("No moves available.");
				}
					
			}
			
			if (_currentCard == null) {
				return;
			}

			//Did user drag card to aces pile?
			AcesPile acepile = (AcesPile) _acesPiles.find( event.getPoint() );
			if (Validator.MayBePlacedOnAcePile(acepile, _trailList)) {
				_currentPile.removeTrailList(_trailList);
				acepile.addTrailList(_trailList);
				repaint();
				return;
			}
			
		
			// .. or the user pile
			PlayPile playpile = (PlayPile) _playPiles.find( event.getPoint() );
			if (Validator.MayBePlacedOnPlayPile(playpile, _trailList)) {
				_currentPile.removeTrailList(_trailList);
				playpile.addTrailList(_trailList);
				repaint();
				return;
			}
			
			_trailList.restoreLocation();	
			_currentPile.addTrailList(_trailList);
			repaint();
		}

	}

	private class MouseMotionHandler implements MouseMotionListener {
		public void mouseMoved(MouseEvent event) {
			if (_playPiles.findCard(event.getPoint()) == null)
				setCursor(Cursor.getDefaultCursor());
			else
				setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
		}

		public void mouseDragged(MouseEvent event) {
			if (_currentCard != null) {
				if(Validator.MayMoveCard(_currentCard))
				{
					_trailList.setLocation(event.getX(), event.getY(), 30);
				}
			}
			repaint();
		}
	}

	private void arrangeCards(Deck deck) {
		if(_playPiles == null || _playPiles.size() == 0)
			return;
		
		int index = 0;
		while (index < deck.size()) {
			for (Pile pile : _playPiles) {
				if (pile != null) {
					Card card = deck.deckCards[index];
					
					//TODO: rules!
					if(pile.column() > 4 || pile.row() > 4)
					{
						card.turnCardUpSide();
					}
					
					pile.addCard(card);
				}
				index++;

				if (index >= deck.size())
					break;
			}
		}
	}
}
